package xyz.labmem.base.core.result

import com.baomidou.mybatisplus.core.metadata.IPage
import io.swagger.annotations.ApiModelProperty
import xyz.labmem.base.core.annotion.DynamicChartColumn
import xyz.labmem.base.core.annotion.DynamicChartColumn2
import xyz.labmem.base.core.annotion.DynamicPageColumn
import xyz.labmem.base.core.annotion.DynamicPageColumnMapping
import xyz.labmem.base.core.common.response.ChartAndColumnRes
import xyz.labmem.base.core.common.response.ComAndColumnRes
import xyz.labmem.base.core.common.response.ComPageAndColumnRes
import xyz.labmem.base.core.common.response.PageColumn
import xyz.labmem.base.core.entity.ModuleVo
import xyz.labmem.base.core.entity.TableList
import xyz.labmem.base.core.tool.*
import java.text.SimpleDateFormat
import java.util.*
import kotlin.reflect.full.memberProperties


/**
 * ResultUtil
 * @Author lty
 * @Date 2021/12/15 10:19
 */

const val SUCCESS_CODE = 0    //请求成功code
const val FAILED_CODE = -1    //请求失败code
const val UNLOGIN_CODE = -2   //未登录code
const val AUTHERROR_CODE = -3   //权限错误code
const val FORMVERIFY_CODE = -10   //表单验证错误code
const val PASSWORD_CODE = -5   //账号或密码错误
const val SUCCESS_DEF_Message = "请求成功"
const val FAILED_DEF_Message = "请求失败"

open class RU {

    companion object {

        val comparator = kotlin.Comparator { key1: Int, key2: Int -> key2.compareTo(key1) }

        fun <T> free(code: Int?, message: String?, data: T?): RV<T> {
            return RV(code, message, data)
        }

        fun <T> success(data: T?): RV<T> {
            return free(SUCCESS_CODE, SUCCESS_DEF_Message, data)
        }

        fun <T> success(lists: ArrayList<ArrayList<ModuleVo>>, arrays : Array<String>, arrayns : Array<String>): RV<TableList<T>> {
            return saveColums(lists, arrays, arrayns)
        }

        fun <T> success(data: T?, message: String?): RV<T> {
            return free(SUCCESS_CODE, message, data)
        }

        fun successMsg(message: String?): RV<Any> {
            return success(null, message)
        }

        fun success(): RV<Any> {
            return success(null)
        }

        fun <T> failed(message: String?, data: T?): RV<T> {
            return free(FAILED_CODE, message, data)
        }

        fun failedMsg(message: String?): RV<Any> {
            return failed(message, null)
        }

        fun <T> failed(data: T?): RV<T> {
            return failed(FAILED_DEF_Message, data)
        }

        fun failed(): RV<Any> {
            return failed(null)
        }

        fun resultJudgment(judgment: Boolean, smsg: String?, fmsg: String?): RV<Any> {
            return if (judgment) successMsg(smsg ?: "操作成功") else failedMsg(fmsg ?: "操作失败")
        }

        fun resultJudgment(judgment: Boolean): RV<Any> {
            return resultJudgment(judgment, null, null)
        }

        fun resultJudgment(success: Int, smsg: String?, fmsg: String?): RV<Any> {
            return if (success > 0) successMsg(smsg ?: "操作成功") else failedMsg(fmsg ?: "操作失败")
        }

        fun resultJudgment(success: Int): RV<Any> {
            return resultJudgment(success, null, null)
        }

        fun resultCount(count: Int): RV<Any> {
            return resultCount(count, "执行成功！", "没有执行数据")
        }

        fun resultCount(count: Int, smsg: String?, fmsg: String?): RV<Any> {
            return if (count > 0) successMsg("${count}条数据${smsg}") else failedMsg("${fmsg}")
        }

        //分页返回
        fun <T> page(page: IPage<T>): RP<List<T>> {
            return RP(SUCCESS_CODE, SUCCESS_DEF_Message, page.records, page.total)
        }

        fun <T> page(data: List<T>, count: Long): RP<List<T>> {
            return RP(SUCCESS_CODE, SUCCESS_DEF_Message, data, count)
        }

        //动态表头分页
        fun <T> chartWithColumn(page: IPage<T>, clazz: Class<T>): RP<ComPageAndColumnRes<T>> {
            return chartWithColumn(page.records, page.total, clazz, null)
        }

        fun <T> chartWithColumn1(page: List<T>, clazz: Class<T>): RP<ChartAndColumnRes<T>> {
            return chartWithColumn1(page, page.size, clazz, null)
        }

        fun <T> chartWithColumn2(page: IPage<T>, clazz: Class<T>): RP<ComPageAndColumnRes<T>> {
            return chartWithColumn2(page.records, page.total, clazz, null)
        }


        //动态表头分页
        fun <T> pageWithColumn(page: IPage<T>, clazz: Class<T>): RP<ComPageAndColumnRes<T>> {
            return pageWithColumn(page.records, page.total, clazz, null)
        }
        //动态表头不分页
        fun <T> pageWithColumn(page: List<T>, clazz: Class<T>): RP<ComAndColumnRes<T>> {
            return pageWithColumn(page, page.size, clazz, null)
        }



        fun <T> pageWithColumn(page: IPage<T>, clazz: Class<T>, flag: String): RP<ComPageAndColumnRes<T>> {
            return pageWithColumn(page.records, page.total, clazz, flag)
        }
        fun <T> chartWithColumn2(pageData: Any, clazz: Class<T>): ArrayList<PageColumn> {
            var properties = pageData.javaClass.kotlin.memberProperties
            var columns =  ArrayList<PageColumn>()
            val fields1 = clazz.getClassAllField()
            fields1.forEach {
                val an = it.getAnnotation(DynamicChartColumn::class.java)
                if (an != null) {
                    columns.add(PageColumn().apply {
                        key = it.name.toCamelCase()
                        value = an.value
                        properties.map { user->
                            if(key == user.name)
                                name = "${user.get(pageData)}"
                        }
                        uint = an.unit
                        order = an.order
                    })

                }
            }
            columns.sortBy { user ->  user.order}
            return columns
        }

        fun <T> chartWithColumn1(
            pageData: List<T>, count: Int, clazz: Class<T>, flag: String?
        ): RP<ChartAndColumnRes<T>> {
            val column = TreeMap<Int, PageColumn>(comparator)
            val hashMap:HashMap<String,String> = HashMap()

            val pit = LinkedList<Int>()
            val fields = clazz.getClassAllField()
            fields.forEach { it ->
                val an = it.getAnnotation(DynamicChartColumn::class.java)
                val apiModelProperty = it.getAnnotation(ApiModelProperty::class.java)
                if (an != null && apiModelProperty!=null) {
                    val i = column.size + 1
                    apiModelProperty?.let { ap ->
                        var p = i
                        if (an != null) {
                            p = an.order
                            if (column.containsKey(p))
                                column[i] = column[p]!!
                            else
                                pit.push(i)
                        }
                        column[p] = PageColumn().apply {
                            key = it.name.toCamelCase()
                            value = an.value
                            name = ap.value.replace("_","-")
                            uint = an.unit
                        }
                        it.name.toCamelCase()?.let { it1 -> hashMap.put(it1,an.unit) }
                    }
                }
            }

            val data = ChartAndColumnRes<T>().apply {
                list = pageData
                this.column = column
                unitMap = hashMap
            }
            return RP(SUCCESS_CODE, SUCCESS_DEF_Message, data, 0)
        }
        fun <T> chartWithColumn(
            pageData: MutableList<T>, count: Long, clazz: Class<T>, flag: String?
        ): RP<ComPageAndColumnRes<T>> {
            val column = TreeMap<Int, PageColumn>(comparator)

            val pit = LinkedList<Int>()
            val fields = clazz.getClassAllField()
            fields.forEach { it ->
                val an = it.getAnnotation(DynamicChartColumn::class.java)
                val apiModelProperty = it.getAnnotation(ApiModelProperty::class.java)
                if (an != null && apiModelProperty!=null) {
                    val i = column.size + 1
                    apiModelProperty?.let { ap ->
                        var p = i
                        if (an != null && an.order>0) {
                            p = an.order
                            if (column.containsKey(p))
                                column[i] = column[p]!!
                            else
                                pit.push(i)
                        }
                        column[p] = PageColumn().apply {
                            key = it.name.toCamelCase()
                            value = an.value
                            this.order = an.order
                        }
                    }
                }
            }

            val data = ComPageAndColumnRes<T>().apply {
                list = pageData
                this.column = column
            }
            return RP(SUCCESS_CODE, SUCCESS_DEF_Message, data, count)
        }
        fun <T> chartWithColumn2(
            pageData: MutableList<T>, count: Long, clazz: Class<T>, flag: String?
        ): RP<ComPageAndColumnRes<T>> {
            val column = TreeMap<Int, PageColumn>(comparator)

            val pit = LinkedList<Int>()
            val fields = clazz.getClassAllField()
            fields.forEach { it ->
                val an = it.getAnnotation(DynamicChartColumn2::class.java)
                val apiModelProperty = it.getAnnotation(ApiModelProperty::class.java)
                if (an != null && apiModelProperty!=null) {
                    val i = column.size + 1
                    apiModelProperty?.let { ap ->
                        var p = i
                        if (an != null && an.order>0) {
                            p = an.order
                            if (column.containsKey(p))
                                column[i] = column[p]!!
                            else
                                pit.push(i)
                        }
                        column[p] = PageColumn().apply {
                            key = it.name.toCamelCase()
                            value = an.value
                            this.order = an.order
                        }
                    }
                }
            }

            val data = ComPageAndColumnRes<T>().apply {
                list = pageData
                this.column = column
            }
            return RP(SUCCESS_CODE, SUCCESS_DEF_Message, data, count)
        }
        fun <T> pageWithColumn(
            pageData: MutableList<T>, count: Long, clazz: Class<T>, flag: String?
        ): RP<ComPageAndColumnRes<T>> {
            val column = TreeMap<Int, PageColumn>(comparator)
            val baseAnn = clazz.getAnnotation(DynamicPageColumnMapping::class.java)
            val showFields = baseAnn?.showField
            val hiedFields = baseAnn?.hiedField
            val pit = LinkedList<Int>()
            val fields = if (baseAnn != null) clazz.getClassAllField() else clazz.declaredFields
            fields.forEach { it ->
                val an = it.getAnnotation(DynamicPageColumn::class.java)
                val apiModelProperty = it.getAnnotation(ApiModelProperty::class.java)
                if (baseAnn == null || baseAnn.showAll) {
                    var hide = false
                    //判断是否隐藏
                    if (an != null && an.hide)
                        hide = true
                    else if (hiedFields != null && hiedFields.contains(it.name))
                        hide = true
                    if (an != null && flag != null && an.flag != flag && an.flag.isNotBlank())
                        hide = true
                    if (!hide) {
                        val i = column.size + 1
                        apiModelProperty?.let { ap ->
                            var p = i
                            if (an != null) {
                                p = an.order
                                if (column.containsKey(p))
                                    column[i] = column[p]!!
                                else
                                    pit.push(i)
                            } else if (showFields != null && showFields.isNotEmpty()) {
                                showFields.forEach { bt ->
                                    if (bt.name == it.name && bt.order >= 0) {
                                        p = bt.order
                                        if (column.containsKey(p))
                                            column[i] = column[p]!!
                                        else
                                            pit.push(i)
                                    }
                                }
                            } else {
                                if (column.containsKey(i) && pit.isNotEmpty()) {
                                    p = pit.pollFirst()
                                } else if (column.containsKey(i) && !column.containsKey(i + 1))
                                    p = i + 1
                            }
                            column[p] = PageColumn().apply {
                                key = it.name.toCamelCase()
                                value = ap.value.replace("_","-")
                            }
                        }
                    }
                } else {
                    if (an != null && (!an.hide || (flag != null && an.flag.isNotBlank() && an.flag != flag))) {
                        apiModelProperty?.let { ap ->
                            column[if (an.order == 0) column.size + 1 else an.order] = PageColumn().apply {
                                key = it.name.toCamelCase()
                                value = ap.value.replace("_","-")
                            }
                        }
                    } else {
                        if (showFields != null && showFields.isNotEmpty()) {
                            showFields.forEach { bt ->
                                if (bt.name == it.name) {
                                    apiModelProperty?.let { ap ->
                                        column[if (bt.order == 0) column.size + 1 else bt.order] =
                                            PageColumn().apply {
                                                key = bt.name.toCamelCase()
                                                value = ap.value.replace("_","-")
                                            }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            val data = ComPageAndColumnRes<T>().apply {
                list = pageData
                this.column = column
            }
            return RP(SUCCESS_CODE, SUCCESS_DEF_Message, data, count)
        }

        fun notPassword(message: String?): RV<Any> {
            return free(PASSWORD_CODE, message, null)
        }

        fun notLogin(message: String?): RV<Any> {
            return free(UNLOGIN_CODE, message, null)
        }

        fun authError(message: String?): RV<Any> {
            return free(AUTHERROR_CODE, message, null)
        }

        fun <T> saveColums(lists: ArrayList<ArrayList<ModuleVo>>, arrays : Array<String>, arrayns : Array<String>)
                : RV<TableList<T>> {
            val tabsds = ArrayList<HashMap<String,String>>()
            for (i in arrayns.indices) {
                var map = HashMap<String,String>()
                map.put("one1",arrayns[i])
                map.put("prop1",arrays[i]+"_NAME")
                map.put("prop2",arrays[i])
                tabsds.add(map);
            }

            var largest = 0;
            lists.forEach {
                largest = if(largest<it.size) it.size else largest
            }
            val tableDatas = ArrayList<HashMap<String,String>>()
            var min =0
            while(min<largest){
                var data = HashMap<String,String>()
                for(i  in lists.indices){
                    if(min < lists.get(i).size){
                        lists.get(i).get(min).name?.let { data.put(arrays[i]+"_NAME", it) }
                        lists.get(i).get(min).value?.let { data.put(arrays[i], it.toString()) }
                    }
                }

                tableDatas.add(data);
                min++;
            }
            val data = TableList<T>().apply {
                this.tabsds = tabsds
                this.tableDatas = tableDatas
            }
            return RV(SUCCESS_CODE, SUCCESS_DEF_Message, data)
        }

        fun <T> pageWithColumn(
            pageData: List<T>, count: Int, clazz: Class<T>, flag: String?
        ): RP<ComAndColumnRes<T>> {
            val column = TreeMap<Int, PageColumn>(comparator)
            val baseAnn = clazz.getAnnotation(DynamicPageColumnMapping::class.java)
            val showFields = baseAnn?.showField
            val hiedFields = baseAnn?.hiedField
            val pit = LinkedList<Int>()
            val fields = if (baseAnn != null) clazz.getClassAllField() else clazz.declaredFields
            fields.forEach { it ->
                val an = it.getAnnotation(DynamicPageColumn::class.java)
                val apiModelProperty = it.getAnnotation(ApiModelProperty::class.java)
                if (baseAnn == null || baseAnn.showAll) {
                    var hide = false
                    //判断是否隐藏
                    if (an != null && an.hide)
                        hide = true
                    else if (hiedFields != null && hiedFields.contains(it.name))
                        hide = true
                    if (an != null && flag != null && an.flag != flag && an.flag.isNotBlank())
                        hide = true
                    if (!hide) {
                        val i = column.size + 1
                        apiModelProperty?.let { ap ->
                            var p = i
                            if (an != null) {
                                p = an.order
                                if (column.containsKey(p))
                                    column[i] = column[p]!!
                                else
                                    pit.push(i)
                            } else if (showFields != null && showFields.isNotEmpty()) {
                                showFields.forEach { bt ->
                                    if (bt.name == it.name && bt.order >= 0) {
                                        p = bt.order
                                        if (column.containsKey(p))
                                            column[i] = column[p]!!
                                        else
                                            pit.push(i)
                                    }
                                }
                            } else {
                                if (column.containsKey(i) && pit.isNotEmpty()) {
                                    p = pit.pollFirst()
                                } else if (column.containsKey(i) && !column.containsKey(i + 1))
                                    p = i + 1
                            }
                            column[p] = PageColumn().apply {
                                key = it.name.toCamelCase()
                                value = ap.value.replace("_","-")
                            }
                        }
                    }
                } else {
                    if (an != null && (!an.hide || (flag != null && an.flag.isNotBlank() && an.flag != flag))) {
                        apiModelProperty?.let { ap ->
                            column[if (an.order == 0) column.size + 1 else an.order] = PageColumn().apply {
                                key = it.name.toCamelCase()
                                value = ap.value.replace("_","-")
                            }
                        }
                    } else {
                        if (showFields != null && showFields.isNotEmpty()) {
                            showFields.forEach { bt ->
                                if (bt.name == it.name) {
                                    apiModelProperty?.let { ap ->
                                        column[if (bt.order == 0) column.size + 1 else bt.order] =
                                            PageColumn().apply {
                                                key = bt.name.toCamelCase()
                                                value = ap.value.replace("_","-")
                                            }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            val data = ComAndColumnRes<T>().apply {
                list = pageData
                this.column = column
            }
            return RP(SUCCESS_CODE, SUCCESS_DEF_Message, data, count.toLong())
        }
    }

}